package com.laoxu.test.rbacdemo.controller;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.laoxu.test.rbacdemo.common.AppProperties;
import com.laoxu.test.rbacdemo.common.Result;
import com.laoxu.test.rbacdemo.config.JWTToken;
import com.laoxu.test.rbacdemo.constant.AppConstant;
import com.laoxu.test.rbacdemo.exception.AppException;
import com.laoxu.test.rbacdemo.model.ActiveUser;
import com.laoxu.test.rbacdemo.model.SysUser;
import com.laoxu.test.rbacdemo.service.SysUserService;
import com.laoxu.test.rbacdemo.service.UserManager;
import com.laoxu.test.rbacdemo.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.startup.UserConfig;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.*;

/**
 *  登录控制器
 */
@Slf4j
@Validated
@RestController
public class LoginController {
    @Autowired
    private UserManager userManager;
    @Autowired
    private SysUserService userService;
    @Autowired
    private AppProperties properties;
    @Autowired
    private ObjectMapper mapper;

    @PostMapping("/login")
    public Result login(
            @NotBlank(message = "{required}") String username,
            @NotBlank(message = "{required}") String password, HttpServletRequest request) throws Exception {
        username = StringUtils.lowerCase(username);
            password = MD5Util.encrypt(username, password);


        final String errorMessage = "用户名或密码错误";
        SysUser user = this.userManager.getUser(username);

        if (user == null||password == null){
            throw new AppException(errorMessage);
        }
        if (!StringUtils.equals(user.getPassword(), password)){
            throw new AppException(errorMessage);
        }
        if (SysUser.STATUS_LOCK.equals(user.getStatus())){
            throw new AppException("账号已被锁定,请联系管理员！");
        }

        // 更新用户登录时间
        this.userService.updateLoginTime(username);
        // 保存登录记录

        String token = JWTUtil.sign(username, password);
        LocalDateTime expireTime = LocalDateTime.now().plusSeconds(properties.getShiro().getJwtTimeOut());
        String expireTimeStr = DateUtil.formatFullTime(expireTime);
        JWTToken jwtToken = new JWTToken(token, expireTimeStr);


        Map<String, Object> userInfo = this.generateUserInfo(jwtToken, user);
        return new Result().ok(userInfo);
    }



    @GetMapping("logout/{id}")
    public Result logout(@NotBlank(message = "{required}") @PathVariable String id) throws Exception {
        try {
            return new Result().ok("退出系统成功");
        } catch (Exception e) {
            String message = "退出系统失败";
            log.error(message, e);
            throw new AppException(message);
        }
    }

    @PostMapping("regist")
    public void regist(
            @NotBlank(message = "{required}") String username,
            @NotBlank(message = "{required}") String password) throws Exception {
        this.userService.regist(username, password);
    }


    /**
     * 生成前端需要的用户信息，包括：
     * 1. token
     * 2. Vue Router
     * 3. 用户角色
     * 4. 用户权限
     * 5. 前端系统个性化配置信息
     *
     * @param token token
     * @param user  用户信息
     * @return UserInfo
     */
    private Map<String, Object> generateUserInfo(JWTToken token, SysUser user) {
        String username = user.getUsername();
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("token", token.getToken());
        userInfo.put("exipreTime", token.getExipreAt());

        Set<String> roles = this.userManager.getUserRoles(username);
        userInfo.put("roles", roles);

        Set<String> permissions = this.userManager.getUserPermissions(username);
        userInfo.put("permissions", permissions);

        user.setPassword("it's a secret");
        userInfo.put("user", user);
        return userInfo;
    }
}
